#include "Player/Player.h"

#include <QDebug>
#include <QMutex>
#include <QScopedPointer>
#include <QUrl>

#include "Common.h"
#include "Settings.h"
#include "MusicLibrary/MusicLibraryManager.h"
#include "Backend/BaseMediaObject.h"
#include "Backend/IPlayBackend.h"
#include "PluginLoader.h"
#include "MetadataLookup/IMetadataLookup.h"
//#include "MetadataLookup/MetadataLookupManager.h"
#include "MetadataLookup/MetadataLookupMgr.h"
#include "SongMetaData.h"
#include "MusicLibrary/IPlayListDAO.h"

#include "SingletonPointer.h"

namespace PhoenixPlayer {

using namespace MetadataLookup;
using namespace MusicLibrary;
using namespace PlayBackend;

Player::Player(QObject *parent)
    : QObject(parent)
    ,m_isInit(false)
    ,m_autoSkipForward(true)
{
    m_playBackend = 0;


//#if defined(SAILFISH_OS) || defined(UBUNTU_TOUCH)
//    mPluginLoader = PluginLoader::instance();
//    mSettings = Settings::instance();
//    mMusicLibraryManager = MusicLibraryManager::instance();
//#else
//    mPluginLoader = SingletonPointer<PluginLoader>::instance ();
//    mSettings = SingletonPointer<Settings>::instance ();
//    mMusicLibraryManager = SingletonPointer<MusicLibraryManager>::instance ();
//#endif
    m_pluginLoader = PluginLoader::instance ();
    m_settings = Settings::instance ();
    m_musicLibraryManager = MusicLibraryManager::instance ();

//    mMetaLookupManager = nullptr;//new MetadataLookupManager(this);
    m_playQueue = QStringList();
    m_playMode = Common::PlayModeOrder;

    if (!m_isInit)
        init ();
}

Player::~Player()
{
//    qDebug()<<"[Player]"<<__FUNCTION__;
//    if (mMetaLookupManager)
//        delete mMetaLookupManager;
//    qDebug()<<"[Player] after "<<__FUNCTION__;
}

//#if defined(SAILFISH_OS) || defined(UBUNTU_TOUCH)
//Player *Player::instance()
//{
//    static QMutex mutex;
//    static QScopedPointer<Player> scp;
//    if (Q_UNLIKELY(scp.isNull())) {
//        qDebug()<<Q_FUNC_INFO<<">>>>>>>> statr new";
//        mutex.lock();
//        scp.reset(new Player(0));
//        mutex.unlock();
//    }
//    return scp.data();
//}
//#endif

void Player::setPluginLoader()
{
    if (m_pluginLoader == nullptr) {
        qDebug()<<"[Player] No mPluginLoader";
        return;
    }
    if (m_playBackend.isNull ()) {
        m_playBackend = m_pluginLoader->getCurrentPlayBackend ();
        if (!PointerValid (EPointer::PPlaybackend))
            return;
//        qDebug()<<"[Player] user playbackend "<<mPlayBackend->getPluginName ();
        m_playBackend->init ();
        m_playBackend->stop ();
    }
    connect (m_pluginLoader,
             &PluginLoader::signalPluginChanged,
             [this](Common::PluginType type) {
        if (type == Common::PluginPlayBackend) {
            if (m_playBackend) {
                m_playBackend->stop ();
                m_playBackend.data ()->deleteLater ();
            }
            m_playBackend = m_pluginLoader->getCurrentPlayBackend ();
            if (!PointerValid (EPointer::PPlaybackend))
                return;
//            qDebug()<<"change playbackend to"<<mPlayBackend->getPluginName ();
            m_playBackend->init ();
            m_playBackend->stop ();
        }
    });

    if (!PointerValid (EPointer::PPlaybackend)) {
        qDebug()<<"[Player] No Playbackend found";
        return;
    }

    // 播放状态改变信号
    connect (m_playBackend.data (),
             &IPlayBackend::stateChanged,
             [this](Common::PlayBackendState state) {
        emit playBackendStateChanged (state);
        emit playBackendStateChanged ((int)state);
    });

    //当一首曲目播放结束后
    connect (m_playBackend.data (),
             &IPlayBackend::finished,
             [this] {
        emit playTrackFinished ();
        if (m_autoSkipForward)
            doPlayByPlayMode ();
//        if (PointerValid (EPointer::PMusicLibraryManager)) {
//            switch (mPlayMode) {
//            case Common::PlayModeOrder: { //顺序播放
////                if (mMusicLibraryManager->lastSongHash () == mMusicLibraryManager->playingSongHash ()) {
////                    mPlayBackend.data ()->stop ();
////                } else {
////                    mMusicLibraryManager->nextSong ();
////                }
//                if (this->forwardTrackHash (false).isEmpty ())
//                    mPlayBackend.data ()->stop ();
//                else
//                    this->skipForward ();
//                break;
//            }
//            case Common::PlayModeRepeatCurrent: { //单曲播放
//                QString playingHash = mMusicLibraryManager->playingSongHash ();
//                PlayBackend::BaseMediaObject obj;

//                QStringList list = mMusicLibraryManager
//                        ->querySongMetaElement (Common::E_FileName, playingHash);
//                if (!list.isEmpty ())
//                    obj.setFileName (list.first ());

//                list = mMusicLibraryManager
//                        ->querySongMetaElement (Common::E_FilePath, playingHash);
//                if (!list.isEmpty ())
//                    obj.setFilePath (list.first ());

//                obj.setMediaType (Common::MediaTypeLocalFile);
//                mPlayBackend.data ()->changeMedia (&obj, 0, true);
//                break;
//            }
//            case Common::PlayModeRepeatAll:  { //循环播放
////                mMusicLibraryManager->nextSong ();
//                this->skipForward ();
//                break;
//            }
//            case Common::PlayModeShuffle: { //随机播放
////                mMusicLibraryManager->randomSong ();
//                this->skipShuffle ();
//                break;
//            }
//            default:
//                break;
//            }
//        }
    });

    //播放失败
    connect (m_playBackend.data (),
             &IPlayBackend::failed,
             [this]() {
//        if (PointerValid (EPointer::PMusicLibraryManager)) {
////            mMusicLibraryManager->nextSong ();
//            this->skipForward ();
//        }
        emit playTrackFailed ();
        if (m_autoSkipForward)
            doPlayByPlayMode ();
    });

    //tick
    connect (m_playBackend.data (),
             &IPlayBackend::tick,
             [this] (quint64 sec) {
        m_currentPlayPos = sec;
        emit playTickActual (sec);
        if (m_currentSongLength <= 0)
            return;

        emit playTickPercent (((qreal)sec/m_currentSongLength) * 100);
    });
}

void Player::setMusicLibraryManager()
{
    if (m_musicLibraryManager == nullptr) {
        qDebug()<<"[Player] no MusicLibraryManager";
        return;
    }
    //播放列表上一首/下一首/随机
    connect (m_musicLibraryManager,
             &MusicLibraryManager::playingSongChanged, [this] () {
        if (!PointerValid (EPointer::PPlaybackend)) {
            qDebug()<<"[Player] Can't connect playingSongChanged ";
            return;
        }
        QString playingHash = m_musicLibraryManager->playingSongHash ();
        m_currentSongLength = getSongLength (playingHash);
        if (!m_playQueue.contains (playingHash)) {
            m_playQueue.append (playingHash);
            qDebug()<<Q_FUNC_INFO<<">>>> append hash to queue "<<playingHash<<" queue size "<<m_playQueue.size ();
        }

        emit trackChanged ();

        PlayBackend::BaseMediaObject obj;
        obj.setFileName (m_musicLibraryManager->queryOne(playingHash, Common::E_FileName));
        obj.setFilePath (m_musicLibraryManager->queryOne(playingHash, Common::E_FilePath));
        obj.setMediaType (Common::MediaTypeLocalFile);
        qDebug()<<"Change song to " << obj.filePath ()<<"  "<<obj.fileName ();
        m_playBackend.data ()->changeMedia (&obj, 0, true);
    });
}

//void Player::setMetaLookupManager()
//{
//    if (mMetaLookupManager == nullptr) {
//        mMetaLookupManager = new MetadataLookupMgr(this);//new MetadataLookupManager(this);
//        connect (mMetaLookupManager,
////                 &MetadataLookupManager::queueFinished,
//                 &MetadataLookupMgr::queueFinished,
//                 [this] {
//            qDebug()<<"========>>> queueFinished <<<<========";
//            delete mMetaLookupManager;
//            mMetaLookupManager = nullptr;
//        });

//        connect (mMetaLookupManager,
////                 &MetadataLookupManager::lookupFailed,
//                 &MetadataLookupMgr::lookupFailed,
//                 [this] (const QString &songHash, IMetadataLookup::LookupType type){
//            emitMetadataLookupResult (type, songHash, false);
//        });

//        connect (mMetaLookupManager,
////                 &MetadataLookupManager::lookupSucceed,
//                 &MetadataLookupMgr::lookupSucceed,
//                 [this]
//                 (QString songHash,
//                 QByteArray result,
//                 IMetadataLookup::LookupType type) {
//            SongMetaData meta;
//            meta.setMeta (Common::SongMetaTags::E_Hash, songHash);
//            switch (type) {
//            case IMetadataLookup::TypeAlbumDate:
//                meta.setMeta (Common::E_AlbumYear, result);
//                break;
//            case IMetadataLookup::TypeAlbumDescription:
//                meta.setMeta (Common::E_AlbumDescription, result);
//                break;
//            case IMetadataLookup::TypeAlbumImage:
//                meta.setMeta (Common::E_AlbumImageUrl, result);
//                break;
//            case  IMetadataLookup::TypeArtistDescription:
//                meta.setMeta (Common::E_ArtistDescription, result);
//                break;
//            case IMetadataLookup::TypeArtistImage:
//                meta.setMeta (Common::E_ArtistImageUri, result);
//                break;
//            case IMetadataLookup::TypeLyrics:
//                meta.setMeta (Common::E_Lyrics, result);
//                break;
//            case IMetadataLookup::TypeTrackDescription:
//                meta.setMeta (Common::E_SongDescription, result);
//                break;
//            default:
//                break;
//            }
//            //TODO 也许通过MusicLibraryManager来管理会更好
//            if (PointerValid (EPointer::PPluginLoader)) {
//                MusicLibrary::IPlayListDAO *dao = mPluginLoader->getCurrentPlayListDAO ();
//                if (dao)
//                    dao->updateMetaData (&meta, true);
//            }
//            emitMetadataLookupResult (type, songHash, true);
//        });
//    }
//}

void Player::setPlayMode(Common::PlayMode mode)
{
    m_playMode = mode;
    qDebug()<<"Play mode changed to "<<m_playMode;
    emit playModeChanged (mode);
    emit playModeChanged (int(mode));
}

void Player::setPlayMode(int mode)
{
    setPlayMode (Common::PlayMode(mode));
}

Common::PlayMode Player::getPlayMode()
{
    return m_playMode;
}

int Player::getPlayModeInt()
{
    return (int)getPlayMode();
}


Common::PlayBackendState Player::getPlayBackendState()
{
    if (!PointerValid((EPointer::PPlaybackend))) {
        Common::PlayBackendState s = Common::PlayBackendStopped;
        return s;
    }
    return m_playBackend.data()->getPlayBackendState();
}

int Player::getPlayBackendStateInt()
{
    return (int)getPlayBackendState();
}

void Player::setAutoSkipForward(bool autoSkipForward)
{
    if (m_autoSkipForward == autoSkipForward)
        return;
    m_autoSkipForward = autoSkipForward;
    emit autoSkipForwardChanged ();
}

bool Player::getAutoSkipForward()
{
    return m_autoSkipForward;
}

void Player::playFromLibrary(const QString &songHash)
{
    m_musicLibraryManager->setPlayingSongHash (songHash);
}

void Player::playFromNetwork(const QUrl &url)
{
    if (!PointerValid (EPointer::PPlaybackend) || url.isEmpty () || !url.isValid ())
        return;
    qDebug()<<Q_FUNC_INFO<<url;

    PlayBackend::BaseMediaObject obj;
    obj.setFilePath (url.toString ());
    obj.setMediaType (Common::MediaTypeUrl);
    m_playBackend.data ()->changeMedia (&obj, 0, true);
}

void Player::addToQueue(const QString &songHash, bool skipDuplicates)
{
    if (!songHash.isEmpty ()) {
        if (skipDuplicates && m_playQueue.contains (songHash))
            return;
        m_playQueue.append (songHash);
    }
}

QStringList Player::getPlayQueue()
{
    return m_playQueue;
}

bool Player::removeQueueItemAt(int index)
{
    if (index < 0)
        return false;
    if (index > m_playQueue.length () -1)
        return false;
    if (m_playQueue.isEmpty ())
        return false;
    m_playQueue.removeAt (index);
    return true;
}

void Player::removeAllQueueItem()
{
    m_playQueue.clear ();
}

QString Player::forwardTrackHash(bool jumpToFirst)
{
    if (m_musicLibraryManager->getCurrentPlayListHash ().isEmpty () && !m_playQueue.isEmpty ()) {
        int index = m_playQueue.indexOf (m_musicLibraryManager->playingSongHash ()) +1;
//        qDebug()<<Q_FUNC_INFO<<">>>>>>> next index is "<<index<<" queue size "<<mPlayQueue.size ();
        if (index >= m_playQueue.size () || m_playQueue.size () == 1) {
             if (jumpToFirst) index = 0;
             else return QString();
        }
        return m_playQueue.at (index);
    }
    if (!jumpToFirst  && (m_musicLibraryManager->playingSongHash () == m_musicLibraryManager->lastSongHash ()))
        return QString();
    return m_musicLibraryManager->nextSong (false);
}

QString Player::backwardTrackHash(bool jumpToLast)
{
    if (m_musicLibraryManager->getCurrentPlayListHash ().isEmpty () && !m_playQueue.isEmpty ()) {
        int index = m_playQueue.indexOf (m_musicLibraryManager->playingSongHash ());
//        qDebug()<<Q_FUNC_INFO<<">>>>>>> pre index is "<<index<<" queue size "<<mPlayQueue.size ();
        if (index == -1) { //no hash found
            if (jumpToLast)
                index = 0;
            else return  QString();
        } else if (index == 0) { //hash is the first song
            if (jumpToLast)
                index = m_playQueue.size () -1; //jump to last song
            else return QString();
        } else {
            index --;
        }
        return m_playQueue.at (index);
    }
    if (!jumpToLast && (m_musicLibraryManager->lastSongHash () == m_musicLibraryManager->playingSongHash ()))
        return QString();
    return m_musicLibraryManager->preSong (false);
}

//void Player::lookupLyric(const QString &songHash)
//{
//    doMetadataLookup (songHash, IMetadataLookup::TypeLyrics);
//}

//void Player::lookupAlbumImage(const QString &songHash)
//{
//    doMetadataLookup (songHash, IMetadataLookup::TypeAlbumImage);
//}

//void Player::lookupAlbumDescription(const QString &songHash)
//{
//    doMetadataLookup (songHash, IMetadataLookup::TypeAlbumDescription);
//}

//void Player::lookupAlbumDate(const QString &songHash)
//{
//    doMetadataLookup (songHash, IMetadataLookup::TypeAlbumDate);
//}

//void Player::lookupArtistImage(const QString &songHash)
//{
//    doMetadataLookup (songHash, IMetadataLookup::TypeArtistImage);
//}

//void Player::lookupArtistDescription(const QString &songHash)
//{
//    doMetadataLookup (songHash, IMetadataLookup::TypeArtistDescription);
//}

//void Player::lookupTrackDescription(const QString &songHash)
//{
//    doMetadataLookup (songHash, IMetadataLookup::TypeTrackDescription);
//}

void Player::togglePlayPause()
{
    if (!PointerValid (EPointer::PPlaybackend))
        return;

    switch (m_playBackend.data ()->getPlayBackendState ()) {
    case Common::PlayBackendPlaying:
        m_playBackend.data ()->pause ();
        break;
    case Common::PlayBackendPaused:
        m_playBackend.data ()->play (m_currentPlayPos);
        break;
    case Common::PlayBackendStopped: {
        if (PointerValid (EPointer::PMusicLibraryManager) && m_autoSkipForward) {
            qDebug()<<__FUNCTION__<<"playbackend stopped";
            QString playingHash = m_musicLibraryManager->playingSongHash ();

            m_currentSongLength = getSongLength (playingHash);
            m_currentPlayPos = 0;

            //设置播放歌曲的hash,使得MusicLibraryManager发送playingSongChanged信号
            //此处是为了使得前端qml界面能够在初始化时候刷新
            m_musicLibraryManager->setPlayingSongHash (playingHash);

            PlayBackend::BaseMediaObject obj;
            QStringList list = m_musicLibraryManager
                    ->querySongMetaElement (Common::E_FileName, playingHash);
            if (!list.isEmpty ())
                obj.setFileName (list.first ());
            list = m_musicLibraryManager
                    ->querySongMetaElement (Common::E_FilePath, playingHash);
            if (!list.isEmpty ())
                obj.setFilePath (list.first ());
            obj.setMediaType (Common::MediaTypeLocalFile);
            qDebug()<<"Change song to " << obj.filePath ()<<"  "<<obj.fileName ();
            m_playBackend.data ()->changeMedia (&obj, 0, true);
        }
        break;
    }
    default:
        break;
    }

}

void Player::play()
{
    if (PointerValid (EPointer::PPlaybackend))
        //TODO: 播放中途暂停时候需要设置当前位置开始播放
        m_playBackend.data ()->play ();
}

void Player::stop()
{
    if (PointerValid (EPointer::PPlaybackend))
        //TODO: 是否需要记住最后播放的歌曲(待后续开发情况决定)
        m_playBackend.data ()->stop ();
}

void Player::pause()
{
    if (PointerValid (EPointer::PPlaybackend))
        m_playBackend.data ()->pause ();
}

//void Player::setVolume(int vol)
//{
//    if (PointerValid (EPointer::PPlaybackend))
//        mPlayBackend.data ()->setVolume (vol);
//}

void Player::setPosition(qreal pos, bool isPercent)
{
    if (!PointerValid (EPointer::PPlaybackend))
        return;

    qDebug()<<"Player setPosition to "<<pos<<" isPercent "<<isPercent;

    if (isPercent) {
        if (m_currentSongLength <= 0)
            return;
        m_playBackend.data ()->setPosition (m_currentSongLength * pos/100);
    } else {
        m_playBackend.data ()->setPosition (pos);
    }
}

void Player::skipForward()
{
    this->playFromLibrary (this->forwardTrackHash ());
}

void Player::skipBackward()
{
    this->playFromLibrary (this->backwardTrackHash ());
}

void Player::skipShuffle()
{
    if (m_musicLibraryManager->getCurrentPlayListHash ().isEmpty () && !m_playQueue.isEmpty ()) {
        QTime time = QTime::currentTime ();
        qsrand(time.second () * 1000 + time.msec ());
        int n = qrand ();
        n = n % m_playQueue.size ();
        this->playFromLibrary (m_playQueue.at (n));
    } else {
        m_musicLibraryManager->randomSong ();
    }
}

void Player::init()
{
    setPluginLoader();
    setMusicLibraryManager();
//    setMetaLookupManager ();
    m_isInit = true;

    qDebug()<<"[Player] after "<<__FUNCTION__;
}

bool Player::PointerValid(Player::EPointer pointer)
{
    bool valid = false;
    switch (pointer) {
    case EPointer::PPlaybackend:
        valid = !m_playBackend.isNull ();
        break;
    case EPointer::PPluginLoader:
        valid = (m_pluginLoader != nullptr);
        break;
    case EPointer::PMusicLibraryManager:
        valid = (m_musicLibraryManager != nullptr);
        break;
//    case EPointer::PPLyricsManager:
//        valid = (mMetaLookupManager != nullptr);
//        break;
    default:
        break;
    }
    return valid;
}

int Player::getSongLength(const QString &hash)
{
    if (hash.isEmpty ())
        return 0;

    if (!PointerValid (EPointer::PMusicLibraryManager))
        return 0;

    QStringList list = m_musicLibraryManager
            ->querySongMetaElement (Common::SongMetaTags::E_SongLength,
                                    hash, true);
    if (!list.isEmpty ()) {
       return list.first ().toULongLong ();
    }
    return 0;
}

//void Player::doMetadataLookup(const QString &songHash,
//                            IMetadataLookup::LookupType type)
//{
//    setMetaLookupManager ();

//    SongMetaData data;
//    QString hash = songHash;
//    if (hash.isEmpty ()) {
//        qDebug()<<__FUNCTION__<<"hash is empty";
//        hash = mMusicLibraryManager->playingSongHash ();
//    }

//    for (int i = (int)Common::SongMetaTags::E_FirstFlag + 1;
//         i < (int)Common::SongMetaTags::E_LastFlag;
//         ++i) {
//        QString str = mMusicLibraryManager->queryOne(hash, Common::SongMetaTags(i), true);
//        if (str.isEmpty())
//            data.setMeta (Common::SongMetaTags(i), QVariant());
//        else
//            data.setMeta (Common::SongMetaTags(i), str);

//    }
//    mMetaLookupManager->lookup (&data, type);
//}

//void Player::emitMetadataLookupResult(IMetadataLookup::LookupType type, const QString &hash, bool succeed)
//{
//    //TODO 添加其他类型的emit
//    switch (type) {
//    case IMetadataLookup::TypeLyrics: {
//        if (succeed)
//            emit lookupLyricSucceed (hash);
//        else
//            emit lookupLyricFailed (hash);
//        break;
//    }
//    case IMetadataLookup::TypeAlbumDescription: {
//        if (succeed)
//            emit lookupAlbumDescriptionSucceed (hash);
//        else
//            emit lookupAlbumDescriptionFailed (hash);
//        break;
//    }
//    case IMetadataLookup::TypeAlbumImage: {
//        if (succeed)
//            emit lookupAlbumImageSucceed (hash);
//        else
//            emit lookupAlbumImageFailed (hash);
//        break;
//    }
//    case IMetadataLookup::TypeAlbumDate: {
//        if (succeed)
//            emit lookupAlbumDateSucceed (hash);
//        else
//            emit lookupAlbumDateFailed (hash);
//        break;
//    }
//    case IMetadataLookup::TypeArtistDescription: {
//        if (succeed)
//            emit lookupArtistDescriptionSucceed (hash);
//        else
//            emit lookupArtistDescriptionFailed (hash);
//        break;
//    }
//    case IMetadataLookup::TypeArtistImage: {
//        if (succeed)
//            emit lookupArtistImageSucceed (hash);
//        else
//            emit lookupArtistImageFailed (hash);
//        break;
//    }
//    case IMetadataLookup::TypeTrackDescription: {
//        if (succeed)
//            emit lookupTrackDescriptionSucceed (hash);
//        else
//            emit lookupTrackDescriptionFailed (hash);
//        break;
//    }
//    case IMetadataLookup::TypeUndefined:
//    default: {
//        if (!succeed)
//            emit metadataLookupFailed (hash);
//        break;
//    }
//    }
//}

void Player::doPlayByPlayMode()
{
    if (PointerValid (EPointer::PMusicLibraryManager) && PointerValid (EPointer::PPlaybackend)) {
        switch (m_playMode) {
        case Common::PlayModeOrder: { //顺序播放
//                if (mMusicLibraryManager->lastSongHash () == mMusicLibraryManager->playingSongHash ()) {
//                    mPlayBackend.data ()->stop ();
//                } else {
//                    mMusicLibraryManager->nextSong ();
//                }
            if (this->forwardTrackHash (false).isEmpty ())
                m_playBackend.data ()->stop ();
            else
                this->skipForward ();
            break;
        }
        case Common::PlayModeRepeatCurrent: { //单曲播放
            QString playingHash = m_musicLibraryManager->playingSongHash ();
            PlayBackend::BaseMediaObject obj;

            QStringList list = m_musicLibraryManager->querySongMetaElement (Common::E_FileName, playingHash);
            if (!list.isEmpty ())
                obj.setFileName (list.first ());

            list = m_musicLibraryManager->querySongMetaElement (Common::E_FilePath, playingHash);
            if (!list.isEmpty ())
                obj.setFilePath (list.first ());

            obj.setMediaType (Common::MediaTypeLocalFile);
            m_playBackend.data ()->changeMedia (&obj, 0, true);
            break;
        }
        case Common::PlayModeRepeatAll:  { //循环播放
//                mMusicLibraryManager->nextSong ();
            this->skipForward ();
            break;
        }
        case Common::PlayModeShuffle: { //随机播放
//                mMusicLibraryManager->randomSong ();
            this->skipShuffle ();
            break;
        }
        default:
            break;
        }
    }
}

}//PhoenixPlayer
